/*
!!! XXX DOES NOT USE BUILT-IN DETECTION FUNCTIONS XXX !!!

alert udp $EXTERNAL_NET any -> $HOME_NET 161 (msg:"SNMP Multiple vendor SNMPv3 HMAC handling authentication bypass attempt"; flow:to_server; content:"|02 01 03|"; content:"|04 01|"; within:2; metadata:service snmp; reference:cve,2008-0960; reference:bugtraq,29623; classtype:attempted-admin; sid:17699; rev:1;)
*/
/*  
 * Vuln Title: Multiple vendor SNMPv3 HMAC handling authentication bypass
 *
 * Copyright (C) 2005-2010 Sourcefire, Inc. All Rights Reserved
 *
 * Written by Sojeong Hong, Sourcefire VRT <shong@sourcefire.com>
 *
 * Auto-generated by shong
 *
 * This file may contain proprietary rules that were created, tested and
 * certified by Sourcefire, Inc. (the "VRT Certified Rules") as well as
 * rules that were created by Sourcefire and other third parties and
 * distributed under the GNU General Public License (the "GPL Rules").  The
 * VRT Certified Rules contained in this file are the property of
 * Sourcefire, Inc. Copyright 2005 Sourcefire, Inc. All Rights Reserved.
 * The GPL Rules created by Sourcefire, Inc. are the property of
 * Sourcefire, Inc. Copyright 2002-2005 Sourcefire, Inc. All Rights
 * Reserved.  All other GPL Rules are owned and copyrighted by their
 * respective owners (please see www.snort.org/contributors for a list of
 * owners and their respective copyrights).  In order to determine what
 * rules are VRT Certified Rules or GPL Rules, please refer to the VRT
 * Certified Rules License Agreement.
 */

#include "sf_snort_plugin_api.h"
#include "sf_snort_packet.h"

#include "so-util_ber.h"

//#define DEBUG
#ifdef DEBUG
#define DEBUG_SO(code) code
#else
#define DEBUG_SO(code)
#endif

/* declare detection functions */
int rule17699eval(void *p);

/* declare rule data structures */
/* flow:to_server; */
static FlowFlags rule17699flow0 = 
{
    FLOW_TO_SERVER
};

static RuleOption rule17699option0 =
{
    OPTION_TYPE_FLOWFLAGS,
    {
        &rule17699flow0
    }
};
// content:"|04|", depth 1, fast_pattern; 
static ContentInfo rule17699content1 = 
{
    (uint8_t *) "|04|", /* pattern (now in snort content format) */
    1, /* depth */             // modified to 3
    0, /* offset */
    CONTENT_FAST_PATTERN|CONTENT_BUF_NORMALIZED, /* flags */  // added CONTENT_RELATIVE
    NULL, /* holder for boyer/moore PTR */
    NULL, /* more holder info - byteform */
    0, /* byteform length */
    0 /* increment length*/
};

static RuleOption rule17699option1 = 
{
    OPTION_TYPE_CONTENT,
    {
        &rule17699content1
    }
};

/* references for sid 17699 */
/* reference: bugtraq "29623"; */
static RuleReference rule17699ref1 = 
{
    "bugtraq", /* type */
    "29623" /* value */
};

/* reference: cve "2008-0960"; */
static RuleReference rule17699ref2 = 
{
    "cve", /* type */
    "2008-0960" /* value */
};

static RuleReference *rule17699refs[] =
{
    &rule17699ref1,
    &rule17699ref2,
    NULL
};
/* metadata for sid 17699 */
/* metadata:service snmp; */
static RuleMetaData rule17699service1 = 
{
    "service snmp"
};

static RuleMetaData rule17699policy1 = 
{
   "policy max-detect-ips drop"
};

static RuleMetaData *rule17699metadata[] =
{
    &rule17699service1,
    &rule17699policy1,
    NULL
};

RuleOption *rule17699options[] =
{
    &rule17699option0,
    &rule17699option1,
    NULL
};

Rule rule17699 = {
   /* rule header, akin to => tcp any any -> any any */
   {
       IPPROTO_UDP, /* proto */
       "$EXTERNAL_NET", /* SRCIP     */
       "any", /* SRCPORT   */
       0, /* DIRECTION */
       "$HOME_NET", /* DSTIP     */
       "161", /* DSTPORT   */
   },
   /* metadata */
   { 
       3,  /* genid */
       17699, /* sigid */
       3, /* revision */
       "attempted-admin", /* classification */
       0,  /* hardcoded priority XXX NOT PROVIDED BY GRAMMAR YET! */
       "PROTOCOL-SNMP Multiple vendor SNMPv3 HMAC handling authentication bypass attempt",     /* message */
       rule17699refs /* ptr to references */
       ,rule17699metadata
   },
   rule17699options, /* ptr to rule options */
   &rule17699eval, /* DO NOT use the built in detection function */
   0 /* am I initialized yet? */
};


/* detection functions */
// #if 0 // Don't compile the detection functions if they're not used
int rule17699eval(void *p) {
    const uint8_t *cursor_normal = 0, *end_of_payload;
    SFSnortPacket *sp = (SFSnortPacket *) p;

    int ret;

    BER_ELEMENT ber_element;

    DEBUG_SO(printf("rule17699eval enter\n");)

    if(sp == NULL)
        return RULE_NOMATCH;

    if(sp->payload == NULL)
        return RULE_NOMATCH;   
             
    // flow:to_server;
    if (checkFlow(p, rule17699options[0]->option_u.flowFlags) <= 0 )
        return RULE_NOMATCH;

    if (getBuffer(sp, CONTENT_BUF_NORMALIZED, &cursor_normal, &end_of_payload) <= 0)
        return RULE_NOMATCH;

    BER_DATA(0x30); // Universal Sequence
    BER_SKIP(0x02); // ldap version
        DEBUG_SO(printf("msgVersion found\n");)
    BER_DATA(0x30); // msgGlobalData
    BER_SKIP(0x02); // msgID
        DEBUG_SO(printf("msgID found\n");)
    BER_SKIP(0x02); // msgMaxSize 
        DEBUG_SO(printf("msgMaxSize found\n");)
    BER_SKIP(0x04); // msgFlags
        DEBUG_SO(printf("msgFlags found\n");)

    /*
     * If msgSecurityModel INTEGER is 3,
     * we need to parse msgSecurityParameters as UsmSecurityParameters structure.
     * Otherwise, return
    */
    // ret is number of bytes available
    ret = ber_get_element(sp, cursor_normal, &ber_element);
    DEBUG_SO(printf("ber_element.type=0x%02x ret=%d ber_element.data_len=%d\n", ber_element.type, ret, ber_element.data_len));

    // Return if error reading or not enough bytes available
    if(ret < 0 || ret != ber_element.data_len)
        return RULE_NOMATCH;

    // returns nonzero on error, probably because not type 0x02
    if(ber_extract_int_val(&ber_element) != 0)
        return RULE_NOMATCH;

    DEBUG_SO(printf("msgSecurityModel=%d\n", ber_element.data.int_val));
    if(ber_element.data.int_val != 3)
        return RULE_NOMATCH;
            
    DEBUG_SO(printf("msgSecurityModel is 3 (msgSecurityParameters's data is UsmSecurityParameters)\n");)

    // Now skip over the element
    cursor_normal += ber_element.total_len;

    BER_DATA(0x04); // msgSecurityParameters
    BER_DATA(0x30); // UsmSecurityParameters
    BER_SKIP(0x04); // msgAuthoritativeEngineID
        DEBUG_SO(printf("msgAuthoritativeEngineID found\n");)
    BER_SKIP(0x02); // msgAuthoritativeEngineBoots 
        DEBUG_SO(printf("msgAuthoritativeEngineBoots found\n");)
    BER_SKIP(0x02); // msgAuthoritativeEngineTime
        DEBUG_SO(printf("msgAuthoritativeEngineTime found\n");)
    BER_SKIP(0x04); // msgUserName
        DEBUG_SO(printf("msgUserName found\n");)
                    
    /*
     * msgAuthenticationParameters OCTET STRING,
     * If data size is 1, the packet is malicious
     */
    // content:"|04 01|", depth 2, relative;
    ret = ber_get_element(sp, cursor_normal, &ber_element);
  
    if(ret < 0)
       return RULE_NOMATCH;

    if(ber_element.data_len == 1)
    {
        DEBUG_SO(printf("msgAuthenticationParameters size = 1\n");)
        return RULE_MATCH;
    }                    

    return RULE_NOMATCH;
}
// #endif // 0 Don't compile the detection functions if they're not used
/*
Rule *rules[] = {
    &rule17699,
    NULL
};
*/
